#include "pccore.h"
#include "imageprovider.h"
#include "ImageProcessor.h"
#include "kcentergreedyint8.h"
#include "pccoremodel.h"
#include "errordialogmanager.h"
#include "cvalgedgedetection.h"
#include <QtConcurrent/QtConcurrent>
#include <opencv2/imgproc.hpp>

PCcore &PCcore::getInstance()
{
    static PCcore _instance;
    return _instance;
}

void PCcore::loadModels(QString resNetModelPath, QString dualModelPath)
{
    (void)QtConcurrent::run([this, resNetModelPath, dualModelPath]() {
        qInfo() << "PCcore::loadModels";

        // 加载 ResNet 模型
        int resNetResult = pcFutre.loadModel(resNetModelPath, m_modelDetal);
        if (resNetResult < 0) {
            qWarning() << "loadResNetModel Fail :" << resNetResult << ":" << pcFutre.getErrorString();
            m_isLoadModel = true;
            // globalState.setabortMode(StepProcess::PreProcess);
            emit respond(false, pcFutre.getErrorString());
            return;
        }

        // 加载 Dual 模型
        int dualResult = pcDual.loadModel(dualModelPath, m_modelDetal);
        if (dualResult < 0) {
            qWarning() << "loadDualModel Fail :" << dualResult << ":" << pcDual.getErrorString();
            m_isLoadModel = true;
            // globalState.setabortMode(StepProcess::PreProcess);
            emit respond(false, pcDual.getErrorString());
            return;
        }

        // 两个模型都成功时执行
        qInfo() << "successful to load both models";
        m_isLoadModel = false;
        // globalState.setabortMode(StepProcess::AIProcess);
        emit respond(true);
        emit modelDetalChange(m_modelDetal);
    });
}

void PCcore::enablePCcore()
{

    ErrorDialogManager::instance().showNonBlockingInfo(
        "成功打开慧眼",
        "特征差异，字符将自动关闭，请注意控制机器速度. 分码功能暂不支持");
    CvAlgEdgeDetection::getInstance().setdiffEable(false);
    CvAlgEdgeDetection::getInstance().set_emphasizeEnable(false);
    CvAlgEdgeDetection::getInstance().restlogoSize();
    updateisenablePCcore(true);
}

void PCcore::setPCcoreROI(int x, int y , int wid, int hei)
{
    qInfo() << "setPCcoreROI : x =" << x << ", y =" << y << ", wid =" << wid << ", hei =" << hei;
    roi = cv::Rect(x ,y,wid, hei);
}

void PCcore::resetPCcoreROI()
{
    qInfo() << "resetPCcoreROI";
    roi = cv::Rect();

}

cv::Mat PCcore::cropImage(cv::Mat &image)
{
    if(roi.empty())
        return image;
    cv::Rect roiTemp = roi;
    roiTemp = roiTemp & cv::Rect(0, 0, image.cols, image.rows);
    return image(roiTemp);
}


PCcore::PCcore(QObject *parent): QObject(parent)
{
    connect(&KCenterGreedyInt8::instance(), &KCenterGreedyInt8::trianStartSignal, this, &PCcore::trianStartSignal);
    connect(&KCenterGreedyInt8::instance(), &KCenterGreedyInt8::trianStartProcess, this, &PCcore::trianStartProcess);
    connect(&KCenterGreedyInt8::instance(), &KCenterGreedyInt8::trianStartFinish, this, &PCcore::trianStartFinish);
    connect(&KCenterGreedyInt8::instance(), &KCenterGreedyInt8::trianStartFinish,this,[this](){
        isTrain = false;
    });
}

PCcore::~PCcore()
{
    m_isLoadModel = false;
}

int PCcore::process(ImageRecord &record , bool display)
{

    //qInfo() << "GO IN MeauPCcore";
    bool isDrawOutput = (ImageProcessor::getInstance().selectedStep() == ImageProcessor::MeauPCcore);
    cv::Mat srcImage = record.imageRote;
    if (srcImage.empty())
    {
        qWarning() << "srcImage is empty.";
        return -1;
    }
    cv::Mat DrawImage  = srcImage.clone(); //record.getStepImage(Cv).clone();
    srcImage = cropImage(srcImage);


    QString outtext;
    cv::Mat outImage , binaryDefect;
    float DefectCore;
    float scale_Target = 500;
    std::vector<std::vector<cv::Point>> contours;
    //qDebug() << "2";

    if (DrawImage.empty())
    {
        qWarning() << "DrawImage is empty.";
        return -1;
    }
    if(!pcFutre.canRun)
    {
        outtext += " 未加载模型\n";
        goto out;
    }
    if(isDrawOutput)
    {
        QWriteLocker locker(&lock);
        lastCvImage = srcImage.clone();
    }


    if(KCenterGreedyInt8::instance().readKnowledgeBase().size() ==
            pcDual.inputAttrs[1].size /2 && isenablePCcore())
    {
        outtext += " 慧眼成功启动\n";
        QElapsedTimer timer;
        timer.start();
        void *result = pcFutre.detect(srcImage);
        if(result)
        {
            outImage = pcDual.detect(result ,
                                     KCenterGreedyInt8::instance().readKnowledgeBase(),
                                     DefectCore).clone();

        }
        outtext += QString(" 累计耗时：%1 ms\n").arg(timer.nsecsElapsed()/1000000);
        outtext += QString(" 当前值 :%1  \n").arg(DefectCore);
        outtext += QString(" 阈值 :%1  \n").arg(get_detectionThreshold());
    }else
    {
        //qDebug() << "1";
        if(isenablePCcore() && ImageProcessor::getInstance().selectedStep() == ImageProcessor::MeauAutoDetect)
        {

            int untrainNum = PCcoreModel::instance().countUntrainedItems();
                //qDebug() << "3:" << ImageProcessor::getInstance().selectedStep() << " untrainNum:" << untrainNum;
            if(untrainNum < PCcoreModel::instance().needTrainDate())
            {
                if(record.getNgCard().getDefects().empty())
                {
                    void *result = pcFutre.detect(srcImage);
                    PCcoreModel::instance().addItem(result , srcImage);
                    if(untrainNum == PCcoreModel::instance().needTrainDate() - 1)
                    {
                        PCcoreModel::instance().emitDataCollectionComplete();
                    }
                }
            }
        }else
        {
            outtext += "请先先激活，并训练慧眼\n";
        }
    }
    if(!outImage.empty())
    {
        updatedetectionCore(DefectCore);
        scale_Target = get_detectionThreshold() * (255 / DefectCore);
        if(scale_Target < 255)
        {
            record.setDefect(25);
            cv::threshold(outImage, binaryDefect, static_cast<int>(scale_Target), 255, cv::THRESH_BINARY);


            cv::findContours(binaryDefect, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);

            double scaleX = static_cast<double>(srcImage.cols) / static_cast<double>(224);
            double scaleY = static_cast<double>(srcImage.rows) / static_cast<double>(224);

            for (auto& contour : contours) {
                for (auto& point : contour) {
                    point.x = static_cast<int>(point.x * scaleX + roi.x);
                    point.y = static_cast<int>(point.y * scaleY + roi.y);
                }
            }
        }
    }

out:
    if(isDrawOutput)
    {
        if(!roi.empty())
            cv::rectangle(DrawImage, roi, cv::Scalar(0, 255, 0), 3);
        cv::drawContours(DrawImage, contours, -1, cv::Scalar(0, 0, 255), 2);
        ImageProvider::getInstance().image2qml(outImage, "Box1");
        ImageProvider::getInstance().image2qml(DrawImage, "Main");
        ImageProcessor::getInstance().setdetectDetail(outtext);
        // 在 DrawImage 上绘制 roiTemp 矩形

        record.setIsSkipDisplay(true);
        record.setStepImage(PCcoreStep, DrawImage);
    }
    else
    {
        cv::Mat image = record.getStepImage(Cv);
        cv::drawContours(image, contours, -1, cv::Scalar(0, 0, 255), 2);
        record.setStepImage(PCcoreStep, image);
    }


    return 0;
}


PCFeature &PCcore::getpcFutre()
{
    return pcFutre;
}

void PCcore::addTrainData()
{
    qInfo() << "PCcore::addTrainData()" ;
    QReadLocker locker(&lock);
    if(lastCvImage.empty())
    {
        qWarning() << "lastCvImage.empty()";
        return;
    }



    void *result = pcFutre.detect(lastCvImage);
    PCcoreModel::instance().addItem(result , lastCvImage);
    ErrorDialogManager::instance().showNonBlockingInfo(
        "成功添加到数据库"
        ,QString("当前还有%1张图片未训练").arg(PCcoreModel::instance().countUntrainedItems()));
}

void PCcore::startTrain()
{
    qInfo() << "PCcore::startTrain ";
    if(isTrain)
    {
        qInfo() << "Fail PCcore::startTrain isTrain";
        return;
    }
    (void)QtConcurrent::run([this]() {
        isTrain = true;
        int count = PCcoreModel::instance().exportEmbedding(KCenterGreedyInt8::instance().embedding);
        if(count == 0)
        {
            ErrorDialogManager::instance().showNonBlockingError(
                "训练慧眼失败" ,
                QString("检查数据，没有训练数据，均已训练完成"));
            isTrain = false;
            return;
        }

        KCenterGreedyInt8::instance().embedding.append(KCenterGreedyInt8::instance().readKnowledgeBase());
        if(int ret = KCenterGreedyInt8::instance().startBuildKnowledgeBase())
        {
            ErrorDialogManager::instance().showNonBlockingError(
                "训练慧眼失败" ,
                QString("检查数据，清空后重新尝试，错误码%1").arg(ret));
            isTrain = false;
            return;
        }
    });
}

void PCcore::clearTrainData()
{
    QVector<int8_t> temp({});
    KCenterGreedyInt8::instance().writeKnowledgeBase(temp);
    PCcoreModel::instance().clearItems();
}
